package com.jsy.common.util.bytecode;

import javassist.*;

import java.io.*;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarOutputStream;

/**
 * @Author: jsy
 * @Date: 2020/5/15 22:06
 * @Description: javassist修改jar包中的class文件
 */
public class ModifyJarClassJavassistExampleJavassist {
    public static void main(String[] args) throws IOException, NotFoundException, CannotCompileException {
//        String inputJarPath = "yourjarfile.jar";
//        String outputJarPath = "yournewjarfile.jar";
        String inputJarPath = "F:\\jsy\\goalong\\goalong-common\\src\\main\\lib\\jimureport-spring-boot-starter-1.9.0-wethink.jar";
        String outputJarPath = "F:\\jsy\\goalong\\goalong-common\\src\\main\\lib\\modify-jimureport-spring-boot-starter-1.9.0-wethink.jar";
        ClassPool pool = ClassPool.getDefault();
        pool.insertClassPath(inputJarPath);
        try (JarFile jarFile = new JarFile(inputJarPath);
             JarOutputStream jos = new JarOutputStream(new FileOutputStream(outputJarPath))) {

            Enumeration<JarEntry> entries = jarFile.entries();
            while (entries.hasMoreElements()) {
                JarEntry entry = entries.nextElement();
                jos.putNextEntry(new JarEntry(entry.getName()));

                if (entry.getName().endsWith(".class")) {
                    String className = entry.getName().replace('/', '.').substring(0, entry.getName().length() - 6);
                    CtClass ctClass = pool.get(className);
                    // 在这里可以对类进行修改
                    modifyClass(className,ctClass);
                    byte[] modifiedClassBytes = ctClass.toBytecode();
                    jos.write(modifiedClassBytes);
                    ctClass.detach();
                } else {
                    try (InputStream is = jarFile.getInputStream(entry)) {
                        byte[] buffer = new byte[1024];
                        int bytesRead;
                        while ((bytesRead = is.read(buffer)) != -1) {
                            jos.write(buffer, 0, bytesRead);
                        }
                    }
                }
                jos.closeEntry();
            }
        }
    }

    private static void modifyClass(String className, CtClass ctClass) {
        if (className.equals("org.jeecg.modules.jmreport.desreport.util.h")){
            try {
                modifyMethod(ctClass);
//                modifyField(ctClass);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    private static void modifyMethod(CtClass ctClass) throws NotFoundException, CannotCompileException {
        CtMethod[] methods = ctClass.getDeclaredMethods("b");
        System.out.println("methods.length = " + methods.length);
        for (CtMethod method : methods) {
            String signature = method.getSignature();
            String longName = method.getLongName();
            System.out.println("signature: " + signature);
            System.out.println("longName: " + longName);
            // 修改指定方法签名的方法体，method.setBody()参数如何访问
            // $args：表示方法的所有参数组成的数组。$1 代表方法的第一个参数 a，$2 代表方法的第二个参数 b。
            if ("(Ljavax/servlet/http/HttpServletRequest;)Z".equals(signature)){
                method.setBody("{System.out.println(j);" +
                        "System.out.println(f);" +
                        "return true;}");
            }
        }
    }

    private static void modifyField(CtClass ctClass) throws NotFoundException, CannotCompileException {
//        CtField field = ctClass.getField("j");
//        ctClass.removeField(field);
        ctClass.addField(CtField.make("private static String test = \"test\";", ctClass));
    }
}    